/** \file    spirit.cpp
  * \brief   Implementation of our xml serializer based on Boost::Spirit parser.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/xml/spirit/src/spirit.cpp,v 1.1 2004/03/22 09:24:09 cscom1r4 Exp $
  */

#include "xml/spirit.h"
#include "spirit.inl"

namespace xml {

//////////////////////
// spirit_attr_enum //
//////////////////////

class spirit_attr_enum : public attribute_enumeration {
private:
	const spirit::element & e;
	spirit::attrs_type::const_iterator i;
public:
	spirit_attr_enum(const spirit::element & elem)
		: e(elem) 
	{
	}
public:
	virtual void first()
	{ 
		i = e._attrs.begin(); 
	}
	virtual string current()
	{ 
		return (*i).first;
	}
	virtual void next()
	{ 
		++i;
	}
	virtual bool end()
	{
		return i == e._attrs.end(); 
	}
};

///////////////////////
// spirit_child_enum //
///////////////////////

class spirit_child_enum : public node_enumeration {
private:
	spirit::element & e;
	spirit::children_type::iterator i;
public:
	spirit_child_enum(spirit::element & elem)
		: e(elem) 
	{
	}
public:
	virtual void first()
	{ 
		i = e._children.begin(); 
	}
	virtual handle current()
	{ 
		return *i;
	}
	virtual void next()
	{ 
		++i;
	}
	virtual bool end()
	{
		return i == e._children.end(); 
	}
};

/////////////////////
// spirit_tag_enum //
/////////////////////

class spirit_tag_enum : public node_enumeration {
private:
	spirit::element & e;
	spirit::children_type::iterator i;
	const string tag;
public:
	spirit_tag_enum(spirit::element & elem, const string & t)
		: e(elem), tag(t)
	{
	}
public:
	virtual void first()
	{
		i = e._children.begin(); 
		next_match();
	}
	virtual handle current() 
	{ 
		return *i;
	}
	virtual void next()
	{ 
		++i;
		next_match();
	}
	virtual bool end()
	{ 
		return i == e._children.end(); 
	}
private:
	void next_match() {
		for (;;) {
			if (i == e._children.end())
				return;
			if ((**i).tag() == tag)
				return;
			++i;
		}
	}
};

////////////
// spirit //
////////////

spirit::spirit()
{
	_root = 0;
}

spirit::~spirit()
{
	clear();
}

void spirit::clear()
{
	delete _root;
	_root = 0;
}

void spirit::create(const string & root_tag)
{
	clear();
	_root = new element(0, root_tag);
}

node spirit::root()
{
	assert(_root);
	return create_node(_root);
}

handle spirit::copy(handle h)
{
	return h;
}

void spirit::release(handle h)
{
}

bool spirit::null(handle h)
{
	return h == 0;
}

string spirit::get_tag(handle h)
{
	return reinterpret_cast<element*>(h)->tag();
}

attribute_enumeration * spirit::get_attributes(handle h)
{
	return reinterpret_cast<element*>(h)->get_attributes();
}

bool spirit::get_attribute(handle h, const string & name, string & value)
{
	return reinterpret_cast<element*>(h)->get_attribute(name, value);
}

void spirit::set_attribute(handle h, const string & name, const string & value)
{
	reinterpret_cast<element*>(h)->set_attribute(name, value);
}

node_enumeration * spirit::get_children(handle h)
{
	return reinterpret_cast<element*>(h)->get_children();
}

node_enumeration * spirit::get_children_by_tag(handle h, const string & tag)
{
	return reinterpret_cast<element*>(h)->get_children_by_tag(tag);
}

handle spirit::create_child(handle h, const string & tag)
{
	return reinterpret_cast<element*>(h)->create_child(tag);
}

void spirit::clear(handle h, bool attr, bool children)
{
	reinterpret_cast<element*>(h)->clear(attr, children);
}
	
void spirit::erase(handle h)
{
	reinterpret_cast<element*>(h)->erase();
}

/////////////////////
// spirit::element //
/////////////////////

inline attribute_enumeration * spirit::element::get_attributes() const
{
	return new spirit_attr_enum(*this);
}

inline node_enumeration * spirit::element::get_children()
{
	return new spirit_child_enum(*this);
}

inline node_enumeration * spirit::element::get_children_by_tag(const string & tag)
{
	return new spirit_tag_enum(*this, tag);
}

} //namespace xml
